<!-- 詞法分析器 -->
<pre>
  <script>
    class XRegExp {
      constructor(source, flag, root = "root") {
        this.table = new Map()
        this.regexp = new RegExp(this.compileRegExp(source, root, 0).source, flag);
        console.log(this.regexp);
        console.log(this.table);
      }

      compileRegExp(source, name, start) {
        if (source[name] instanceof RegExp) {
          return {
            source: source[name].source,
            length: 0
          };
        }
        let length = 0;
        console.log(source)
        console.log(name)
        let regexp = source[name].replace(/\<([^>]+)\>/g, (str, $1) => {
          this.table.set(start + length, $1);
          
          ++length;
          let r = this.compileRegExp(source, $1, start + length);
          length += r.length;
          return "(" + r.source + ")";
        });
        return {
          source: regexp,
          length: length
        }
      }

      exec(string){
        let r = this.regexp.exec(string);
        for(let i = 0; i< r.length; i++){
          if(r[i] != void 0){
            r[this.table.get(i-1)] = r[i];
          }
        }
        return r;
      }

      get lastIndex(){
        return this.regexp.lastIndex;
      }

      set lastIndex(value){
        return this.regexp.lastIndex = value;
      }
    }

    function scan(str) {
      let regexp = new XRegExp({
        InputElement: "<Whitespace>|<LineTerminator>|<Comments>|<Token>",
        Whitespace: / /,
        LineTerminator: /\n/,
        Comments: /\/\*(?:[^*]|\*[^\/])*\*\/|\/\/[^\n]*/,
        Token: "<Literal> |<Keywords>| <Identifer> | <Punctuator>",
        Literal: "<NumericLiteral> |<BooleanLiteral> |<StringLiteral> | <NullLiteral>",
        NumericLiteral: /(?:[1-9][0-9]*|0)(?:\.[0-9]*)?|\.[0-9]+/,
        BooleanLiteral: /true |false/,
        StringLiteral: /\"(?:[^"\n]|\\[\s\S])*\"|\' (?:[^'\n]\\[\s\S])*\'/,
        NullLiteral: /null/,
        Identifer: /[a-zA-Z_$][a-zA-Z0-9_$]*/,
        Keywords: /if|else|for|function/,
        Punctuator: /\+|\,|\?|\:|\{|\}|\.|\(|\=|\<|\+\+|\=\=|\=\>|\*|\)|\[|\]|;/
      }, "g", "InputElement")

      while (regexp.lastIndex < str.length) {
        let r = regexp.exec(str);
        console.log(r);
        //document . write(r)
        if (!r[0].length)
          break;
      }
    }

    scan(`
      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
          let cell = document.createElement("div");
          cell.classList.add("cell");
          cell.innerText = pattern[i * 3 + j] == 2 ? "X": 
            pattern[i * 3 + j] == 1 ? "O" : "";
          cell.addEventListener("click", () => userMove(j, i));
          board.appendChild(cell);
        }
        board.appendChild(document.createElement("br"))
      }
    `)
  </script>
</pre>